using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Data;
using System.IO;
using Microsoft.WindowsCE.Forms;

namespace PocketPC_AdventureGame
{
	/// <summary>
	/// Summary description for Form1.
	/// </summary>
	public class Game : System.Windows.Forms.Form, GameActions
	{
        private static String programPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);

        private Dictionary<String, Screen> screens = new Dictionary<string,Screen>();
        private Screen currentScreen;

      
		private Image backBuffer;
        private GameObject exit = new GameObject("exit", new Bitmap(programPath + "\\exit_button.png"));
		private Player player;
		private Inventory inventory = new Inventory( new Rectangle(208, 50, 30, 220) );

        private System.Windows.Forms.Timer clock;
		private GameObject dragObject = null;
		private String status = "";
		private Brush textBrush = new SolidBrush(Color.WhiteSmoke);
		private Font textFont;  // set in constructor
        StringFormat textFormat = new StringFormat(StringFormatFlags.NoWrap | StringFormatFlags.NoClip);
        private int updateTime;    //when last update was called, used to calculate frame time for movement

		public Game()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();

            player = new Player(this, new Bitmap(programPath + "\\player.png"));
            player.position.X = 90;
            player.position.Y = 190;
            player.speed = 50f;
            exit.position.X = 212;
            exit.position.Y = 10;

            //create corridor screen
            Screen cScr = new Screen(new Bitmap(programPath + "\\levels\\corridor\\foreground.png"), new Bitmap(programPath + "\\levels\\corridor\\background.png"), new Bitmap(programPath + "\\levels\\corridor\\walkway.png"));
            GameObject coin = new GameObject("Coin", new Bitmap(programPath + "\\levels\\corridor\\coin.png"));
            coin.position.X = 110;
            coin.position.Y = 44;
            cScr.screenObjects.Add(coin);
            Exit corrLeft = new Exit(cScr, "LeftEntrance", new Bitmap(programPath + "\\levels\\corridor\\left_exit.png"));
            corrLeft.position.X = 130;
            corrLeft.position.Y = 250;
            corrLeft.AddExitInteraction(this, player, corrLeft);
            cScr.screenObjects.Add(corrLeft);
            screens["Corridor"] = cScr;

            //create jungle screen
            Screen scr = new Screen(new Bitmap(programPath + "\\levels\\jungle\\foreground.png"), new Bitmap(programPath + "\\levels\\jungle\\background.png"), new Bitmap(programPath + "\\levels\\jungle\\walkway.png"));
            Exit door = new Exit(cScr, "Door", new Bitmap(programPath + "\\levels\\jungle\\door.png"));
            door.position.X = 09;
            door.position.Y = 24;
            door.pickable = false;
            door.AddState("Open", new Bitmap(programPath + "\\levels\\jungle\\door_open.png"));
            door.AddExitInteraction(this, player, corrLeft);
            scr.screenObjects.Add(door);
            GameObject coconut = new GameObject("Coconut", new Bitmap(programPath + "\\levels\\jungle\\coconut.png"));
            coconut.position.X = 50;
            coconut.position.Y = 244;
            scr.screenObjects.Add(coconut);
            GameObject leaf = new GameObject("Leaf", new Bitmap(programPath + "\\levels\\jungle\\leaf.png"));
            leaf.position.X = 84;
            leaf.position.Y = 157;
            scr.screenObjects.Add(leaf);
            GameObject slab = new GameObject("Slab", new Bitmap(programPath + "\\levels\\jungle\\slab.png"));
            slab.position.X = 150;
            slab.position.Y = 37;
            slab.pickable = false;
            slab.AddState("Pressed", new Bitmap(programPath + "\\levels\\jungle\\slab_pressed.png"));
            slab.AddStateChangeInteraction(this, coconut, slab, "Pressed", true);
            slab.AddStateChangeInteraction(this, coconut, door, "Open", true);
            slab.AddStateChangeInteraction(this, player, slab, "Pressed", false);
            slab.AddStateChangeInteraction(this, player, door, "Open", false);
            slab.AddNoneInteraction(this, slab, "Default");
            slab.AddNoneInteraction(this, door, "Default");
            scr.screenObjects.Add(slab);
            screens["Jungle"] = scr;
            currentScreen = scr;


            backBuffer = new Bitmap(this.Width, this.Height);


            LogFont lf = new LogFont();
            lf.Escapement = 900;
            lf.Height = 20;
            lf.PitchAndFamily = Microsoft.WindowsCE.Forms.LogFontPitchAndFamily.Swiss;
            textFont = Font.FromLogFont(lf);

            clock.Enabled = true;
            updateTime = Environment.TickCount;
		}

		protected override void OnPaint(PaintEventArgs e) 
		{
			Graphics buffer = Graphics.FromImage(backBuffer);
			buffer.DrawImage( currentScreen.background, 0, 0 );
            foreach (GameObject obj in currentScreen.screenObjects) obj.Draw(buffer);

			player.Draw(buffer);
            currentScreen.foreground.Draw(buffer);
			inventory.Draw(buffer);
			exit.Draw(buffer);

			buffer.DrawString(status, textFont, textBrush, 50, 250, textFormat );

			e.Graphics.DrawImage(backBuffer, 0, 0);
		}

		protected override void OnPaintBackground(PaintEventArgs e)
		{
		}


		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			base.Dispose( disposing );
		}
		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            this.clock = new System.Windows.Forms.Timer();
            this.SuspendLayout();
            // 
            // clock
            // 
            this.clock.Interval = 50;
            this.clock.Tick += new System.EventHandler(this.Update);
            // 
            // Game
            // 
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
            this.AutoValidate = System.Windows.Forms.AutoValidate.Disable;
            this.ClientSize = new System.Drawing.Size(320, 240);
            this.ControlBox = false;
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
            this.Location = new System.Drawing.Point(0, 0);
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "Game";
            this.Text = "Adventure game";
            this.WindowState = System.Windows.Forms.FormWindowState.Maximized;
            this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.Game_MouseUp);
            this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Game_MouseDown);
            this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.Game_MouseMove);
            this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>

		static void Main() 
		{
			Application.Run(new Game());
		}

		private void Game_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			dragObject = inventory.HitTest(e.X, e.Y);
			if( dragObject != null ) 
			{
				dragObject.position.Width = dragObject.originalWidth;
				dragObject.position.Height = dragObject.originalHeight;
			}
		}

		private void Game_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			//exit?
			if( exit.HitTest(e.X, e.Y) ) Close();

			//move player if not dragging
			if( dragObject == null ) 
			{
				player.MoveTo(e.X, e.Y);
			}
			else 
			{	//check target for drop
				bool interacted = false;
				foreach( GameObject obj in currentScreen.screenObjects ) 
				{
					if( obj != dragObject && dragObject.Collide(obj) ) 
					{
						player.MoveTo(e.X, e.Y);
						player.setGoalAction( Player.GoalActions.DROP, dragObject );
						interacted = true;
						break;
					}
				}
				if (!interacted ) PickUp(dragObject);

			}
			dragObject = null;

			//pick up object when player arrives?
            player.setGoalAction(Player.GoalActions.NONE, null);
            foreach (GameObject obj in currentScreen.screenObjects) 
			{
				if( obj.pickable && obj.HitTest(e.X, e.Y) )
				{
					player.setGoalAction( Player.GoalActions.PICK_UP, obj );
					return;
				}
			}
		}


		public void PickUp(GameObject obj) 
		{
			if( obj.pickable ) 
			{
                currentScreen.screenObjects.Remove(obj);
				inventory.Add(obj);
			}
		}

		public void Drop(GameObject source) 
		{
			inventory.Remove(source);
            currentScreen.screenObjects.Add(source);
		}

		public void ShowText(String message) 
		{
			status = message;
		}

        public void SwitchScreen(Exit exit)
        {
            player.position.Location = exit.position.Location;
            player.MoveTo(exit.position.X, exit.position.Y);
            currentScreen = exit.targetScreen;
        }

		private void Update(object sender, System.EventArgs e)
		{
            float elapsed = (Environment.TickCount - updateTime) / 1000f;
            updateTime = Environment.TickCount;
            foreach (GameObject obj in currentScreen.screenObjects) obj.Update(elapsed);
            inventory.Update(elapsed);
            player.Update(elapsed);
            foreach (GameObject targetObj in currentScreen.screenObjects)
			{
				//collide with player
				if(player.Collide(targetObj)) targetObj.Interact(player);

                //collide rest of objects
                foreach (GameObject sourceObj in currentScreen.screenObjects) if (targetObj != sourceObj) sourceObj.Collide(targetObj);
			}
            this.Refresh();
		}

		private void Game_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
		{
			if( dragObject != null ) 
			{
				dragObject.position.X = e.X-dragObject.position.Width/2;
				dragObject.position.Y = e.Y-dragObject.position.Width/2;
				status = "pos: "+e.X+", "+e.Y;
			}
		}


        public Location GetLocatationAt(int x, int y)
        {
            return currentScreen.GetLocatationAt(x, y);

        }

        public Location FindClosestLocation(int x, int y)
        {
            return currentScreen.FindClosestLocation(x, y);
        }


	}
}
